package com.boot.persistence.service.association;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.boot.persistence.mapper.IMapper;
import com.boot.persistence.model.AssociationModel;
import com.boot.persistence.model.BaseModel;
import com.boot.persistence.service.ServiceImpl;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 霜寒 <1621856595@qq.com>
 * @className AssociationServiceImpl
 * @description 多对多关联查询业务实现
 * @date 2019/11/13 20:26
 **/

@SuppressWarnings("all")
public abstract class AssociationServiceImpl<Tid extends Serializable, Mid extends Serializable, Nid extends Serializable,
        T extends AssociationModel<Tid, Mid, Nid>, M extends BaseModel<Mid>, N extends BaseModel<Nid>,
        Mapper extends IMapper<T>, MMapper extends BaseMapper<M>, NMapper extends BaseMapper<N>>
        extends ServiceImpl<Tid, T, Mapper>
        implements IAssociationService<Tid, Mid, Nid, T, M, N, Mapper, MMapper, NMapper> {

    private MMapper mMapper;

    private NMapper nMapper;

    public AssociationServiceImpl(Mapper mapper, MMapper mMapper, NMapper nMapper) {
        super(mapper);
        this.mMapper = mMapper;
        this.nMapper = nMapper;
    }

    @Override
    public Collection<N> m2n(Mid mid) {
        T model = this.createModel();
        model.setMid(mid);
        List<T> tList = mapper.selectList(Wrappers.query(model));
        Set<Nid> nids = tList.stream().map(record -> record.nid())
                .collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(nids)) {
            return Collections.emptyList();
        } else {
            return nMapper.selectBatchIds(nids);
        }
    }

    @Override
    public Collection<N> m2n(List<Mid> mids) {
        T model = this.createModel();
        List<T> tList = mids.stream().map(mid -> {
            model.setMid(mid);
            return mapper.selectList(Wrappers.query(model));
        }).reduce((s1, s2) -> {
            s1.addAll(s2);
            return s1;
        }).orElseGet(ArrayList::new);
        Set<Nid> nids = tList.stream().map(record -> record.nid())
                .collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(nids)) {
            return Collections.emptyList();
        } else {
            return nMapper.selectBatchIds(nids);
        }
    }

    @Override
    public Collection<M> n2m(Nid nid) {
        T model = this.createModel();
        model.setNid(nid);
        List<T> tList = mapper.selectList(Wrappers.query(model));
        Set<Mid> mids = tList.stream().map(record -> record.mid())
                .collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(mids)) {
            return Collections.emptyList();
        } else {
            return mMapper.selectBatchIds(mids);
        }
    }

    @Override
    public Collection<M> n2m(List<Nid> nids) {
        T model = this.createModel();
        List<T> tList = nids.stream().map(nid -> {
            model.setNid(nid);
            return mapper.selectList(Wrappers.query(model));
        }).reduce((s1, s2) -> {
            s1.addAll(s2);
            return s1;
        }).orElseGet(ArrayList::new);
        Set<Mid> mids = tList.stream().map(record -> record.mid())
                .collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(mids)) {
            return Collections.emptyList();
        } else {
            return mMapper.selectBatchIds(mids);
        }
    }

    @Override
    public MMapper getMMapper() {
        return mMapper;
    }

    @Override
    public NMapper getNMapper() {
        return nMapper;
    }
}
